package pl.cezary.butler.walili.server.db.tasks;

import org.springframework.dao.DataAccessException;
import pl.cezary.butler.walili.server.ServerTask;
import java.sql.ResultSet;
import java.sql.Connection;
import java.sql.Date;
import java.sql.Statement;
import java.sql.SQLException;
import java.util.EnumMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.jdbc.core.ResultSetExtractor;
import pl.cezary.butler.walili.server.db.tables.ZadPolozenie;
import pl.cezary.butler.walili.server.db.tables.ZadReszta;
import pl.cezary.butler.walili.server.db.tables.ZadaniaId;
import pl.cezary.butler.walili.server.db.utils.TableDefinitionUtils;

/**
 *
 * @author Przemysław Bałdyga
 */
public class UpdateTaskTask extends UpdateTask {

    private static final Logger log = Logger.getLogger(UpdateTaskTask.class.getName());
    private final String target;
    private final String location;
    private final String targetUrl;
    private int status;
    private int priority;
    private final String mime;
    private final int lastUserProcessing;
    private final Date lastProcessingDate;

    public UpdateTaskTask(ServerTask z) {
        status = z.getStatus().ordinal();
        priority = z.getPriorytet();
        lastProcessingDate = convert(z.getDataPrzetwarzania());
        lastUserProcessing = ((IUserId) z.getOstatniPrzetwarzajacy()).getId();
        target = z.getCel();
        targetUrl = z.getCelURL().toString();
        location = z.getPolozenie();
        mime = z.getMimeType();        
    }

    @Override
    public void execute() {
        int priorytetDb = -1;
        int idPolozenie = ZadPolozenie.EMPTY_LOCATION_ID;
        int idReszta = 0;
        boolean flag = false;
        if (location != null) {
            idPolozenie = getJdbcTemplate().queryForIntIfEmpty(TableDefinitionUtils.getQueryForColumn(ZadPolozenie.id_polozenie)
                    + " WHERE polozenie = ?", location);
            assert (idPolozenie != 0);
        }
        if (target != null) {

            final Map<ZadReszta, Integer> zadReszta = getJdbcTemplate().query("SELECT id_reszta,priorytet FROM zad_reszta WHERE celUrl = ?", new ResultSetExtractor<Map<ZadReszta, Integer>>() {

                @Override
                public Map<ZadReszta, Integer> extractData(ResultSet rs) throws SQLException, DataAccessException {
                    final Map<ZadReszta, Integer> result = new EnumMap(ZadReszta.class);
                    if (rs.next()) {
                        result.put(ZadReszta.priorytet, rs.getInt(ZadReszta.priorytet.name()));
                        result.put(ZadReszta.id_reszta, rs.getInt(ZadReszta.id_reszta.name()));
                    } else {
                        log.log(Level.WARNING, "No entries in table zad reszta for target{0}", target);
                    }
                    int count = 1;
                    while (rs.next()) {
                        ++count;
                    }
                    if (count > 1) {
                        if(log.isLoggable(Level.FINE))
                        log.log(Level.FINE, "Found to many ({1}) entries in table zad reszta for target {0}", new Object[]{target, count});
                    }
                    return result;
                }
            }, targetUrl);

            flag = !zadReszta.isEmpty();
            if (flag) {
                priorytetDb = zadReszta.get(ZadReszta.priorytet);
                idReszta = zadReszta.get(ZadReszta.id_reszta);
                priority = Math.min(priority, priorytetDb);
            }

            if (idReszta == 0) {
                idReszta = getJdbcTemplate().insert(ZadReszta.class,
                        getIdFactory().generateId(), target, targetUrl, status, priority, lastUserProcessing, lastProcessingDate);
                log.log(Level.INFO, "Entry with id #{0} was added in table zad_reszta despite it's an update task", idReszta);
            } else {
                log.log(Level.FINE, "Record with id #{0} in table zad_reszta was updated", idReszta);
                getJdbcTemplate().update("UPDATE zad_reszta SET status=?, priorytet=?,  id_user=?, data_przetwarzania=?, mime_type=? WHERE id_reszta=?",
                        status, priority, lastUserProcessing, lastProcessingDate,mime, idReszta);
            }
            assert (idReszta != 0);
        }
                

        if (location == null && target == null) {
            log.warning("Both target and location are null");
            return;
        } else {
            //FIXME to może być lepsze niż to co jest w zadanie new task
            if (!getJdbcTemplate().queryForObject(
                    String.format("SELECT EXISTS(SELECT 1 FROM %s WHERE %s=? AND %s=?)",
                    ZadaniaId.id_polozenie.getTable(), ZadaniaId.id_polozenie, ZadaniaId.id_reszta), Boolean.class, idPolozenie, idReszta)) {
                getJdbcTemplate().insert(ZadaniaId.class, idPolozenie, idReszta);
                if (flag) {
                    log.log(Level.WARNING, "Connection between was created id_polozenie: {0}, id_reszta: {1} despite previously existing record in zad_reszta", new Object[]{idPolozenie, idReszta});
                } else {
                    log.log(Level.FINE, "Connection between was created id_polozenie: {0}, id_reszta: {1}", new Object[]{idPolozenie, idReszta});
                }
            } else {
                log.log(Level.FINE, "Found existing connection between id_polozenie: {0}, id_reszta: {1}", new Object[]{idPolozenie, idReszta});
            }
        }
    }

    @Override
    public String toString() {
        return "UpdateTaskTask{" + "target=" + target + ", location=" + location + ", status=" + status + ", priority=" + priority + ", mime=" + mime + ", lastUserProcessing=" + lastUserProcessing + ", lastProcessingDate=" + lastProcessingDate + '}';
    }        

    private static Date convert(java.util.Date d) {
        return new Date(d.getTime());
    }
}
